﻿using System;
using RayDen.Library.Components.Surface;
using RayDen.Library.Core;
using RayDen.Library.Core.Primitives;
using RayDen.RayEngine.Core.Types;

namespace RayDen.RayEngine.Core.Surface {


    [Serializable]
    public abstract class BxDFBase  : ISurfaceMaterial {
        public BxDFType Type;
        public abstract float[] Eval(ref Vector wo, ref Vector wi, ref Normal N);
        public abstract void Sample(ref Vector wo, ref Normal N, ref Normal shadeN, float u0, float u1, float u2,out  BsdfSample sample,BxDFType type = BxDFType.AllTypes);

        public static Vector GlossyReflection(Vector wo, float exponent, Normal shadN, float u0, float u1) {
            var shadeN = shadN;
            float phi = 2f * MathLab.M_PI * u0;
            float cosTheta = (float)MathLab.Pow(1f - u1, exponent);
            float sinTheta = MathLab.Sqrt(1f - cosTheta * cosTheta);
            float x = (float)Math.Cos(phi) * sinTheta;
            float y = (float)Math.Sin(phi) * sinTheta;
            float z = cosTheta;

            Vector dir = -wo;
            float dp = Vector.Dot(ref shadeN, ref dir);
            Vector w = dir - (2f * dp) * shadeN.ToVec();

            Vector u;
            if (Math.Abs(shadeN.x) > .1f) {
                var a = new Vector(0f, 1f, 0f);
                u = Vector.Cross(ref a, ref w);
            }
            else {
                Vector a = new Vector(1f, 0f, 0f);
                u = Vector.Cross(ref a, ref w);
            }
            u = u.Normalize();
            Vector v = Vector.Cross(ref w, ref u);

            return x * u + y * v + z * w;
        }

        public virtual float Pdf(ref Vector wo, ref Vector wi, BxDFType bxDFType) {
            return MathLab.INVTWOPI;
        }

        public string Name
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        BrdfType ISurfaceMaterial.Type
        {
            get { throw new NotImplementedException(); }
        }

        public float ContinuationProbability
        {
            get { throw new NotImplementedException(); }
        }

        public bool IsDiffuse()
        {
            throw new NotImplementedException();
        }

        public bool IsSpecular()
        {
            throw new NotImplementedException();
        }

        public bool IsRefractive()
        {
            throw new NotImplementedException();
        }

        public void f(ref Vector wo, ref Vector wi, ref Normal N, ref RgbSpectrum in_fs, out RgbSpectrum fs, BrdfType types = BrdfType.Diffuse)
        {
            throw new NotImplementedException();
        }

        public RgbSpectrum Sample_f(ref Vector wo, out Vector wi, ref Normal N, ref Normal shadeN, ref RgbSpectrum in_fs, float u0, float u1, float u2, ref SurfaceTextureData surfaceData, out float pdf, out BsdfEvent bsdfEvent)
        {
            throw new NotImplementedException();
        }

        public RgbSpectrum Sample_f(ref Vector wo, out Vector wi, ref Normal N, ref Normal shadeN, float u0, float u1, float u2, out float pdf, out bool specularBounce)
        {
            throw new NotImplementedException();
        }

        public float Pdf(ref Vector wo, ref Vector wi)
        {
            throw new NotImplementedException();
        }

        public RayDen.Library.Entity.Scene.TextureInfo AlphaTexture
        {
            get { throw new NotImplementedException(); }
        }

        public bool TransparentShadows { get; set; }


        public BrdfClass Class
        {
            get ;set;
        }


        public RgbSpectrum Sample_f(ref Vector wo, out Vector wi, ref Normal N, ref Normal shadeN, ref RgbSpectrum in_fs, float u0, float u1, float u2, ref SurfaceTextureData surfaceData, out float pdf, out bool specularBounce)
        {
            throw new NotImplementedException();
        }
    };
}
